﻿using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Linq;
using CI.Interfaces;

namespace CI.Organism
{
    /// <summary>Collection class containing a list of Gene's</summary>
    [CollectionDataContract]
    public class GeneCollection : List<IGene>, IGeneCollection
    {
        /// <summary>
        /// Take this parents Genes and create a new Gene Collection to be put in the new child organism
        /// Mutate the current Genes and return a new one, deep class level mutation
        /// </summary>
        /// <param name="mutationRate">mutation rate to be applied</param>
        /// <param name="organism">child Organism it will be going into</param>
        /// <returns>new gene collection for child</returns>
        public IGeneCollection Mutate(double mutationRate, IOrganism organism)
        {
            #region Argument check
            if (organism == null)
                throw new ArgumentException("Organism");
            #endregion

            var childGenes = new GeneCollection();

            // create a new set of genes
            foreach (var gene in this)
            {
                childGenes.Add(gene.Mutate(mutationRate, organism));
            }

            // mutate removing genes from the collection
            if (Mutation.MutateState(mutationRate) && (childGenes.Count > 0))
            {
                childGenes.RemoveRange(Mutation.CollectionSelect(childGenes), 1);
            }

            // mutate adding new genes to the collection
            if (Mutation.MutateState(mutationRate))
            {
                // add a new one
                childGenes.Add(Gene.CreateNewGene(mutationRate, organism));
            }

            return childGenes;
        }

        /// <summary>
        /// Find the gene with the specifed guid
        /// </summary>
        /// <param name="guid">guid to find</param>
        /// <returns>Gene</returns>
        public IGene Find(Guid guid)
        {
            return this.FirstOrDefault(gene => gene.Guid == guid);
        }
    }
}